<?php
namespace App\Common\Services;


use App\Exceptions\ApiException;
use App\Services\CommonBaseService;
use App\Common\Facades\OssFacade;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\FFMpeg;
use Illuminate\Support\Facades\Log;

class UploadFileService extends CommonBaseService
{

    /**
     * 文件mineType类型
     * @var array
     */
    private $mineTypeList = [];

    /**
     * 文件扩展名
     * @var array
     */
    private $fileExt = ['png', 'jpg', 'jpeg', 'gif', 'mp4', 'mp3', 'ico', '3gpp', 'ac3', '3gpp', 'ac3',
        'asf', 'au', 'css', 'csv', 'doc', 'dot', 'dtd', 'dwg', 'dxf', 'gif', 'jp2', 'jpe',
        'mp2', 'mp3', 'mp4', 'mpeg', 'mpg', 'mpp', 'ogg', 'pdf', 'pot', 'pps', 'ppt', 'rtf', 'svf',
        'tif', 'tiff', 'txt', 'wdb', 'wps', 'xhtml', 'xlc', 'xlm', 'xls', 'xlt', 'xlw', 'xml',
        'zip', 'xlsx','docx','webp'];

    /**
     * 文件扩展名
     * @var string
     */
    private $nowFileExt = '';

    /**
     * 文件限制大小,默认20M
     * @var int
     */
    private $limitSize = 1024 * 1024 * 50;

    /**
     * 保存的路径
     * @var string
     */
    private $basePath = './';
    /**
     * 设置文件路径
     * @var string
     */
    private $filePath = '/files';
    /**
     * 上传文件字段
     * @var string
     */
    private $fileField = 'file';

    /**
     * 获取本地路径
     * @param $file
     * @return string
     */
    public function getLocalPath($file = '')
    {
        return resource_path('upload') . $file;
    }


    public function testHH(){
        return 'sb';
    }

    /**
     * 上传图片文件
     * @param $request
     * @param string $fileField
     * @param array|string $fileExt
     * @param bool $isUploadOss
     * @return array
     */
    public function upload($request, $fileField = 'file', $fileExt = [], $isUploadOss = true,$isReName=false)
    {
        $this->fileField = $fileField;
        if (!empty($fileExt)) {
            $this->setFileExt($fileExt);
        }
        $this->validate($request);
        $result = $this->saveLocal($request,$isReName);
        $localPath=$this->getLocalPath().$result['path'];
        if (strpos($result['mimeType'], 'image') !== false) {
            list($width, $height) = getimagesize($localPath);
            $result['resolution'] = $width . '*' . $height;
        }
        $result['url'] = $request->root() .'/resources'. $result['path'];
        $path = $this->getLocalPath() . $this->filePath;
        $useFfmpeg= config('app.USE_FFMPEG');
        if ($useFfmpeg&&!empty($result['mimeType'])&&strpos($result['mimeType'], 'video') !== false) {
            $ffmpeg=FFMpeg::create(array(
                'ffmpeg.binaries'  => config('app.ffmpeg.ffmpeg_binaries'),
                'ffprobe.binaries' => config('app.ffmpeg.ffprobe_binaries'),
                'timeout'          =>config('app.ffmpeg.timeout'), // The timeout for the underlying process
                'ffmpeg.threads'   => config('app.ffmpeg.ffmpeg_threads'),   // The number of threads that FFMpeg should use
            ));
            $picFilename = $this->getFilename($path,'jpg');
            $video = $ffmpeg->open($localPath);

            $fileSavePath=$path.'/'.$picFilename;
            $video->frame(TimeCode::fromSeconds(1))->save($fileSavePath);
            if(file_exists($fileSavePath)){
                $checkFileNameStr=str_replace('.'.$result['ext'],'',$picFilename);
                if (preg_match('/^.*[,\.#%\'\+\*\:;^`\{\}\(\)\[\]\s]/', $checkFileNameStr)) {
                    $picFilename=  preg_replace('/[,\.#%\'\+\*\:;^`\{\}\(\)\[\]\s]/','-', $checkFileNameStr).'.'.$result['ext'];
                }
                $coverOssUrl = OssFacade::uploadToOss($fileSavePath, $picFilename, md5_file($fileSavePath),'share_center',$isReName);
                $result['pic']=$coverOssUrl;//封面图
            }
        }
        if ($isUploadOss) {
            $filename = $result['original_filename'];
            $checkFileNameStr=str_replace('.'.$result['ext'],'',$filename);
            if (preg_match('/^.*[,\.#%\'\+\*\:;^`\{\}\(\)\[\]\s]/', $checkFileNameStr)) {
                $filename=  preg_replace('/[,\.#%\'\+\*\:;^`\{\}\(\)\[\]\s]/','-', $checkFileNameStr).'.'.$result['ext'];
            }
            $ossUrl = OssFacade::uploadToOss($localPath, $filename, md5(file_get_contents($localPath)),'share_center',$isReName);
            $result['url'] = $ossUrl;
            //Log::info(json_encode($result));
            if (!empty($result['mimeType'])&&strpos($result['mimeType'], 'video') !== false) {
                // 视频截图
                $picFilename = $this->getFilename($path,'jpg');
                $fileSavePath = $path.'/'.$picFilename;
                downloadFile($ossUrl.'?x-oss-process=video/snapshot,t_1000,f_jpg,w_800,h_600,m_fast', $fileSavePath);
                if (file_exists($fileSavePath)) {
                    $coverOssUrl = OssFacade::uploadToOss($fileSavePath, $picFilename, md5_file($fileSavePath),'share_center',$isReName);
                    $result['pic']=$coverOssUrl;//封面图
                }
            }
        }
        return $result;
    }

    /**
     * 上传Base64图片
     * @param $request
     * @param string $fileField
     * @param array|string $fileExt
     * @param bool $isUploadOss
     * @return array
     */
    public function uploadImgBase64($data, $fileExt = 'jpg', $host='',$selectFileName='',$isUploadOss = true)
    {
        if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $data, $result)) {
            $type = $result[2];
            if (in_array($type, array('pjpeg', 'jpeg', 'jpg', 'gif', 'bmp', 'png'))) {
                $this->nowFileExt = strtolower($type);
                $path =  $this->filePath;//$this->basePath.$this->filePath;
                $path.="/" .date('md') . "/".uniqid()."/";
                $localPath=$this->getLocalPath().$path;
                if(empty($selectFileName)){
                    $filename = $this->getFilename($localPath);
                }else{
                    $filename=  $selectFileName.'.'.$this->nowFileExt;
                }

                $filepath = $localPath . '/' . $filename;
                if (!file_exists($localPath)) {
                    mkdir($localPath, 0777, true);
                }
                if (file_put_contents($filepath, base64_decode(str_replace($result[1], '', $data)))) {
                    $size = filesize($filepath);
                    $s = getimagesize($filepath);
                    $width = empty($s[0]) ? '' : $s[0];
                    $height = empty($s[1]) ? '' : $s[1];
                    $result = [
                        'path' => $path.$filename,
                        'size' => $size,
                        'filename' => $filename,
                        'original_filename' => $filename,
                        'ext' => $this->nowFileExt,
                        'resolution' => $width . '*' . $height,
                        'url' => $host.'/resources'.$path.$filename,
                        'mimeType' => 'image/' . $this->nowFileExt
                    ];
                    if ($isUploadOss) {
                        $ossUrl = OssFacade::uploadToOss($filepath, $filename, md5(file_get_contents($filepath)));
                        $result['url'] = $ossUrl;
                    }
                    return $result;
//                    echo '图片上传成功</br><img src="' .$img_path. '">';
                } else {
                    throw new ApiException(1101);

                }
            } else {
                //文件类型错误
                throw new ApiException(1101);
            }

        } else {
            //文件错误
            throw new ApiException(1101);
        }
        return false;
    }

    /**
     * 上传文本转为文件
     * @param $request
     * @param string $fileField
     * @param array|string $fileExt
     * @param bool $isUploadOss
     * @return array
     */
    public function uploadTextToFile($data, $fileExt = '', $isUploadOss = true)
    {
        if (!empty($fileExt)) {
            $this->nowFileExt = strtolower($fileExt);
            $path = $this->getLocalPath() . $this->filePath;
            $filename = $this->getFilename($path);
            $filepath = $path . '/' . $filename;
            if (!file_exists($path)) {
                mkdir($path, 0777, true);
            }
            if (file_put_contents($filepath, $data)) {
                $size = filesize($filepath);
                $s = getimagesize($filepath);
                $result = [
                    'path' => $filepath,
                    'size' => $size,
                    'filename' => $filename,
                    'original_filename' => $filename,
                    'ext' => $this->nowFileExt,
                    'url' => ''
                ];
                if ($isUploadOss) {
                    $ossUrl = OssFacade::uploadToOss($filepath, $filename, md5(file_get_contents($filepath)));
                    $result['url'] = $ossUrl;
                }
                return $result;
            }
        }
        return false;
    }

    /**
     * 设置扩展名
     * @param array $fileExt
     * @return $this
     */
    public function setFileExt($fileExt)
    {
        if (empty($fileExt)) {
            return;
        }
        if (!is_array($fileExt)) {
            $fileExt = explode(',', $fileExt);
        }
        $this->fileExt = $fileExt;
        return $this;
    }

    /**
     * 上传验证
     * @param $request
     * @return bool
     * @throws ApiException
     */
    private function validate($request)
    {
        $fileInfo = $request->file($this->fileField);
//        if (!$request->hasFile($this->fileField) || !$fileInfo->isValid()) {
//            throw new ApiException(30002);
//        }
        if (!$this->checkFileExt($fileInfo)) {
            throw new ApiException(1101);
        }
        if (!$this->checkLimitSize($fileInfo)) {
            $limit = floor($this->limitSize / (1024 * 1024)) . 'M';
            throw new ApiException(1102, ['limit' => $limit]);
        }
        $this->checkDirectory($this->filePath);
        return true;
    }

    /**
     * 检查文件扩展名
     * @param $fileInfo
     * @return bool
     */
    private function checkFileExt($fileInfo)
    {
        $fileType = strtolower($fileInfo->getClientOriginalExtension());
        if (!$fileType || !in_array($fileType, $this->fileExt)) {
            return false;
        }
        $this->nowFileExt = strtolower($fileType);
        return true;
    }

    /**
     * 验证文件大小
     * @param $fileInfo
     * @return bool
     */
    private function checkLimitSize($fileInfo)
    {
        $clientSize = $fileInfo->getSize();
        if ($clientSize > $this->limitSize) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 检验文件夹，不存在则创建
     * @param $path
     */
    private function checkDirectory($path)
    {
        $folders = explode('/', $path);
        $basePath = $this->getLocalPath();//$this->basePath;
        foreach ($folders as $item) {
            if (empty($item)) {
                continue;
            }
            if (strrpos($basePath, '/') !== strlen($basePath) - 1) {
                $basePath .= '/';
            }
            $basePath .= $item;
            $this->makeDir($basePath);
        }
    }

    /**
     * 新增文件目录
     * @param $path
     * @return mixed
     */
    private function makeDir($path)
    {
        if (is_dir($path)) {
            return $path;
        } else {
            mkdir($path, 0777, true);
            return $path;
        }
    }

    /**
     * 上传保存到本地
     * @param $request
     * @return array
     */
    private function saveLocal($request,$isReName=false)
    {
        $fileInfo = $request->file($this->fileField);

        $path = $this->filePath;//$this->basePath.$this->filePath;
        $path.="/" .date('md') . "/";
        $OldFilename = $fileInfo->getClientOriginalName();
        if($isReName){
            $localPath=$this->getLocalPath().$path;
            $filename = $this->getFilename($localPath);
        }else{
            $path.= uniqid()."/";
            $localPath=$this->getLocalPath().$path;
            $filename= $OldFilename;
        }
        $fileSize = $fileInfo->getSize();
        $mimeType = $fileInfo->getMimeType();
        $fileInfo->move($localPath, $filename);
//        Log::info($this->filePath.'/'.$filename);
        return [
            'path' => $path.$filename,
            'size' => $fileSize,
            'filename' => $filename,
            'original_filename' => $OldFilename,
            'ext' => $this->nowFileExt,
            'mimeType' => $mimeType
        ];
    }

    /**
     * 获取文件名
     * @param $path
     * @return string
     */
    private function getFilename($path,$ext='')
    {
        $suffix=empty($ext)? $this->nowFileExt:$ext;
        $fileName = date('YmdHis') . mt_rand(100, 999) . '.' . $suffix;
        if (file_exists($path .'/'. $fileName)) {
            return $this->getFileName($path,$ext);
        }
        return $fileName;
    }

    /**
     * 设置文件路径
     * @param string $path
     * @return $this
     */
    public function setFilePath($path)
    {
        $this->filePath = $path;
        return $this;
    }

    /**
     * 设置文件大小
     * @param string $maxSize
     * @return $this
     */
    public function setMaxSize($maxSize = '')
    {
        if ($maxSize && is_numeric($maxSize)) {
            $this->limitSize = $maxSize;
        }
        return $this;
    }

    /**
     * 设置文件mineType
     * @param array $mineType
     * @return $this
     */
    public function setMineType($mineType = [])
    {
        if ($mineType) {
            $this->mineTypeList = $mineType;
        }
        return $this;
    }
}
